﻿using System.Collections.Generic;
using System.Reflection;
using Common.RefitHttp;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Nacos.V2;
using Refit;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using Common.Identity;
using Demo03.RestClient;

namespace System;

/// <summary>
/// Refit 扩展
/// </summary>
public static class RefitExtensions
{
    /// <summary>
    /// 扩展Refit, 使用Nacos服务发现配置BaseUrl
    /// </summary>
    /// <param name="builder"></param>
    /// <param name="assemblies"></param>
    public static void AddRefitWithServiceDiscovery(this WebApplicationBuilder builder, params Assembly[] assemblies)
    {
        builder.Services.AddHttpClient();

        builder.Services.AddTransient<AuthHeaderHandler>();

        List<Type> restClientTypeList = new();
        foreach (var enumerable in assemblies.Select(assembly =>
                     assembly.GetTypes().Where(it => it.IsInterface && it.IsDefined(typeof(HttpClientAttribute)))))
        {
            restClientTypeList.AddRange(enumerable);
        }

        foreach (var type in restClientTypeList)
        {
            builder.Services.AddTransient(type, provider =>
            {
                var logger = provider.GetService<ILogger<Program>>();
                var authHeaderHandler = provider.GetService<AuthHeaderHandler>();
                var httpClientFactory = provider.GetService<IHttpClientFactory>();
                HttpClient httpClient;
                if (authHeaderHandler == null)
                {
                    httpClient = httpClientFactory?.CreateClient() ?? new HttpClient();
                }
                else
                {
                    httpClient = new HttpClient(authHeaderHandler);
                }
                
                var httpClientAttribute = type.GetCustomAttribute<HttpClientAttribute>();
                var nacosNamingService = provider.GetService<INacosNamingService>();
                var instance = nacosNamingService.SelectOneHealthyInstance(httpClientAttribute.ServiceName)
                    .ConfigureAwait(false).GetAwaiter().GetResult();
                var host = $"{instance.Ip}:{instance.Port}";
                var baseUrl = instance.Metadata.TryGetValue("secure", out _) ? $"https://{host}" : $"http://{host}";
                logger?.LogDebug("service: {@serviceName}, baseUrl: {@baseUrl}, {@token}", httpClientAttribute.ServiceName,
                    baseUrl, IdentityContext.Current?.BearerToken);
                httpClient.BaseAddress = new Uri(baseUrl);
                return RestService.For(type, httpClient);
            });
        }
    }
}